package wiBase.baseObject;

import java.util.ArrayList;
import wiBase.WiObject;
import wiBase.baseInterface.OnEventSchedulerListener;

/**
 * Event of simulation.
 * @extends WiObject have OnOutputStreamListener object.
 * @implement Runnable: for scheduler call in queue Thread pool.
 */
public class Event extends WiObject implements Runnable {

    public static final int TYPE_SEND = 0x1;
    public static final int TYPE_RECEIVE = 0x10;
    public static final int TYPE_FORWARD = 0x100;
    public static final int TYPE_SLEEP = 0x1000;
    public static final int TYPE_WAKE = 0x10000;
    public String type = "";
    public String time = "";
    public String timeReceive = "";
    public String sourcePort = "";
    public String sourceId = "";
    public String remainEnergy = "";
    public String packetId = "";
    public String destPort = "";
    public String destId = "";
    public String bufferLength = "";
    public String nodeId = "";
    public String reason = "";
    // move
    public String currX = "";
    public String currY = "";
    public String currZ = "";
    public String destX = "";
    public String destY = "";
    public String destZ = "";
    public String speed = "";
    /**
     * callback for schedule.
     */
    OnEventSchedulerListener _listener = null;
    
    /**
     * if type='send/forward ': contain list event forward/receive. 
     */
    public ArrayList<Event> lstEventReceive = new ArrayList<>();

    public Event() {
    }

    @Override
    public String toString() {
//	return (type==null ||type.equals(""))?"":"type="+type;
	return output(false);
    }

    public String toString(boolean CLRF) {
	return output(CLRF);
    }
    /**
     * @same: toString with new line for each fields.
     */
    public String output(boolean CLRF) {
	StringBuilder result = new StringBuilder("Event{");
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("type", type));
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("time", time));
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("timeReceive", timeReceive));
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("sourcePort", sourcePort));
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("sourceId", sourceId));
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("remainEnergy", remainEnergy));
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("packetId", packetId));
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("destPort", destPort));
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("destId", destId));
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("bufferLength", bufferLength));
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("nodeId", nodeId));
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("speed", speed));
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("reason", reason));
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("currX", currX));
	result.append(getString("currY", currY));
	result.append(getString("currZ", currZ));
	if (CLRF) {
	    result.append("\n");
	}
	result.append(getString("destX", destX));
	result.append(getString("destY", destY));
	result.append(getString("destZ", destZ));


	return result.toString();
    }

    public String getString(String type, String value) {
	if (value != null && !value.equals("")) {
	    return type + "=" + value + ",";
	}
	return "";
    }

    public long getTime() {
	return (long) (Double.parseDouble(time) * 1E9);		// Nanosecond
    }

    public long getTimeReceive() {
	try {
	    return (long) (Double.parseDouble(timeReceive) * 1E9);		// Nanosecond
	} catch (NumberFormatException e) {
	    System.out.println(time + " :number exception");
	    return -1;
	}
    }

    public void setTraceSchedulerListener(OnEventSchedulerListener listener) {
	this._listener = listener;
    }

    @Override
    public void run() {
	if (_listener != null) {
	    _listener.write(this);
	}
    }

    // seriable is an event
    public void run(String type, WiObject... seriable) {
	if (getOutputListener() == null) {
	    System.out.println("Event line 155: output listener NULL");
	    return;
	}
	// call back
	getOutputListener().write(type, seriable);
    }

    public Event deepCopy() {
	Event newObject = new Event();

	newObject.type = this.type;
	newObject.time = this.time;
	newObject.timeReceive = this.timeReceive;
	newObject.sourcePort = this.sourcePort;
	newObject.sourceId = this.sourceId;
	newObject.remainEnergy = this.remainEnergy;
	newObject.packetId = this.packetId;
	newObject.destPort = this.destPort;
	newObject.destId = this.destId;
	newObject.bufferLength = this.bufferLength;
	newObject.nodeId = this.nodeId;
	newObject.reason = this.reason;
	// move
	newObject.currX = this.currX;
	newObject.currY = this.currY;
	newObject.currZ = this.currZ;
	newObject.destX = this.destX;
	newObject.destY = this.destY;
	newObject.destZ = this.destZ;
	newObject.speed = this.speed;
	newObject._listener = this._listener;
	return newObject;
    }
    /**
     * inflate variable matching with attrName with value=attrValue.
     */
    public static Event parseValue(String[] attrName, String[] attrValue) {
	Event _event = new Event();
	for (int i = 0; i < attrName.length; ++i) {
	    switch (attrName[i]) {
		case "type":
		    _event.type = attrValue[i];
		    break;
		case "time":
		    _event.time = attrValue[i];
		    break;
		case "packet-id":
		    _event.packetId = attrValue[i];
		    break;
		case "node-id":
		    _event.nodeId = attrValue[i];
		    break;
		case "reason":
		    _event.reason = attrValue[i];
		    break;
		case "source-id":
		    _event.sourceId = attrValue[i];
		    break;
		case "source-port":
		    _event.sourcePort = attrValue[i];
		    break;
		case "dest-id":
		    _event.destId = attrValue[i];
		    break;
		case "dest-port":
		    _event.destPort = attrValue[i];
		    break;
		case "remain-energy":
		    _event.remainEnergy = attrValue[i];
		    break;
		case "curr-x":
		    _event.currX = attrValue[i];
		    break;
		case "curr-y":
		    _event.currY = attrValue[i];
		    break;
		case "curr-z":
		    _event.currZ = attrValue[i];
		    break;
		case "dest-x":
		    _event.destX = attrValue[i];
		    break;
		case "dest-y":
		    _event.destY = attrValue[i];
		    break;
		case "dest-z":
		    _event.destZ = attrValue[i];
		    break;
		case "speed":
		    _event.speed = attrValue[i];
		    break;
	    }
	}
	return _event;
    }
}
